home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Educational
/
Chaos
/
Source
/
UserPath.m
< prev
Wrap
Text File
|
1995-06-12
|
10KB
|
380 lines
/*
* UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
*
* You may freely copy,distribute and re-use the code in this example. NeXT
* disclaims any warranty of any kind, expressed or implied, as to its fitness
* for any particular purpose
*
*/
#import "UserPath.h"
#import <mach_init.h>
#import <appkit/graphics.h>
#import <appkit/errors.h>
#import <math.h>
#import <libc.h>
static NXZone *upZone = NULL;
NXZone *userPathZone()
/* Creates a unique zone for use by all user paths */
{
if (!upZone) {
upZone = NXCreateZone(vm_page_size, vm_page_size, 1);
}
return upZone;
}
UserPath *newUserPath()
/* Creates a new User Path in the zone returned by userPathZone */
{
UserPath *up;
up = (UserPath *)NXZoneMalloc(userPathZone(), sizeof(UserPath));
up->max = 32;
up->points = (float *)NXZoneMalloc(userPathZone(),
sizeof(float) * up->max);
up->ops = (char *)NXZoneMalloc(userPathZone(),
(2 + (up->max / 2)) * sizeof(char));
up->ping = NO;
return up;
}
void freeUserPath(UserPath *up)
/* Frees User Path and its associated buffers */
{
free(up->points);
free(up->ops);
free(up);
return;
}
void growUserPath(UserPath *up)
/*
* grows the associated buffers as necessary. buffer size doubles on each
* call. You never need to call grow directly as it is called as needed by the
* methods and functions which add elements into the buffer
*/
{
/* double the size of the internal buffers */
up->max *= 2;
up->points = (float *)NXZoneRealloc(userPathZone(), up->points,
sizeof(float) * up->max);
up->ops = (char *)NXZoneRealloc(userPathZone(), up->ops,
(2 + (up->max / 2)) * sizeof(char));
return;
}
void beginUserPath(UserPath *up, BOOL cache)
/*
* Call this to start generating a user path. The cache argument specifies if
* you want the user path cached at the server (i.e. dps_ucache). In either
* case, the UserPath object will automatically calculate the bounding box for
* the path and add the dps_setbbox operator.
*/
{
up->numberOfPoints = up->numberOfOps = 0;
up->cp.x = up->cp.y = 0;
up->bbox[0] = up->bbox[1] = 1.0e6;
up->bbox[2] = up->bbox[3] = -1.0e6;
if (cache) {
up->ops[up->numberOfOps++] = dps_ucache;
}
up->ops[up->numberOfOps++] = dps_setbbox;
up->opForUserPath = 0;
return;
}
void endUserPath(UserPath *up, int op)
/*
* Call this to stop filling the path. Note this does not send the userpath to
* the server -- use sendUserPath. The op argument should be one of the
* following:
* dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
* dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
* These are defined in <dpsclient/dpsNext.h.
*/
{
up->opForUserPath = op;
return;
}
void UPdebug(UserPath *up, BOOL shouldPing)
/*
* Sets ping to YES so that after each time a user path is sent down to the
* window server, an NXPing() is sent after. The purpose is to catch PostScript
* errors that may be generated by the user path. sendUserPath brackets the
* download and the NXPing() in an NX_DURING... NX_HANDLER construct. Normally
* ping is NO.
*/
{
up->ping = shouldPing;
return;
}
int sendUserPath(UserPath *up)
/*
* Call this to send the path down to the server. If ping==YES (set via
* debug:), the function will send an NXPing() after the Path. In any event,
* code is bracketed by a NX_DURING ... NX_HANDLER construct which will try to
* catch postscript errors. If ping==NO (the default) it is unlikely to catch
* errors, with ping==YES it will. Whether you can recover or not is another
* matter. sendUserPath returns 0 on success and -1 on failure. If no previous
* endUserPath: has been sent, will return -2 and will not send the path to the
* server.
*/
{
NXHandler exception;
exception.code = 0;
if (up->opForUserPath != 0) {
NX_DURING
DPSDoUserPath(up->points, up->numberOfPoints, dps_float, up->ops,
up->numberOfOps, up->bbox, up->opForUserPath);
if (up->ping) {
NXPing();
}
NX_HANDLER
exception = NXLocalHandler;
NX_ENDHANDLER
if (exception.code) {
NXReportError(&exception);
if (exception.code == dps_err_ps) {
return -1;
}
} else {
return 0;
}
}
return -1;
}
void checkBoundingBox(UserPath *up, float x, float y)
/* Checks if bounding box needs to be enlarged based on x and y */
{
if (x < up->bbox[0]) {
up->bbox[0] = x;
}
if (y < up->bbox[1]) {
up->bbox[1] = y;
}
if (x > up->bbox[2]) {
up->bbox[2] = x;
}
if (y > up->bbox[3]) {
up->bbox[3] = y;
}
return;
}
void addPts(UserPath *up, float x, float y)
/* adds x and y to user path. Updates bounding box as necessary */
{
if (!((up->numberOfPoints + 2) < up->max)) {
growUserPath(up);
}
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
checkBoundingBox(up, x, y);
return;
}
void addOp(UserPath *up, int op)
/*
* adds operator to user path. Operator should be one of the following:
* dps_moveto, dps_rmoveto, dps_lineto, dps_rlineto, dps_curveto,
* dps_rcurveto, dps_arc, dps_arcn, dps_arct, dps_closepath.
*/
{
up->ops[up->numberOfOps++] = op;
return;
}
void add(UserPath *up, int op, float x, float y)
/*
* adds operator and x and y to user path. Operator should be one of the
* operators above
*/
{
if (!((up->numberOfPoints + 2) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = op;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
checkBoundingBox(up, x, y);
return;
}
void UPmoveto(UserPath *up, float x, float y)
/* adds <x y moveto> to user path and updates bounding box */
{
add(up, dps_moveto, x, y);
up->cp.x = x;
up->cp.y = y;
return;
}
void UPrmoveto(UserPath *up, float x, float y)
/* adds <x y rmoveto> to user path and updates bounding box */
{
if (!((up->numberOfPoints + 2) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = dps_rmoveto;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
up->cp.x += x;
up->cp.y += y;
checkBoundingBox(up, up->cp.x, up->cp.y);
return;
}
void UPlineto(UserPath *up, float x, float y)
/* adds <x y lineto> to user path and updates bounding box */
{
add(up, dps_lineto, x, y);
up->cp.x = x;
up->cp.y = y;
return;
}
void UPrlineto(UserPath *up, float x, float y)
/* adds <x y rlineto> to user path and updates bounding box */
{
if (!((up->numberOfPoints + 2) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = dps_rlineto;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
up->cp.x += x;
up->cp.y += y;
checkBoundingBox(up, up->cp.x, up->cp.y);
return;
}
void UPcurveto(UserPath *up, float x1, float y1, float x2, float y2, float x3,
float y3)
/* adds <x1 y1 x2 y2 curveto> to user path and updates bounding box */
{
addPts(up, x1, y1);
addPts(up, x2, y2);
add(up, dps_curveto, x3, y3);
up->cp.x = x3;
up->cp.y = y3;
return;
}
void UPrcurveto(UserPath *up, float dx1, float dy1, float dx2, float dy2,
float dx3, float dy3)
/* adds <x1 y1 x2 y2 rcurveto> to user path and updates bounding box */
{
if (!((up->numberOfPoints + 6) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = dps_rcurveto;
up->points[up->numberOfPoints++] = dx1;
up->points[up->numberOfPoints++] = dy1;
up->points[up->numberOfPoints++] = dx2;
up->points[up->numberOfPoints++] = dy2;
up->points[up->numberOfPoints++] = dx3;
up->points[up->numberOfPoints++] = dy3;
checkBoundingBox(up, up->cp.x + dx1, up->cp.y + dy1);
checkBoundingBox(up, up->cp.x + dx2, up->cp.y + dy2);
checkBoundingBox(up, up->cp.x + dx3, up->cp.y + dy3);
up->cp.x = dx3;
up->cp.y = dy3;
return;
}
void UParc(UserPath *up, float x, float y, float r, float ang1, float ang2)
/* adds <x y r ang1 ang2 arc> to user path and updates bounding box */
{
if (!((up->numberOfPoints + 5) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = dps_arc;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
up->points[up->numberOfPoints++] = r;
up->points[up->numberOfPoints++] = ang1;
up->points[up->numberOfPoints++] = ang2;
checkBoundingBox(up, x + r, y + r);
checkBoundingBox(up, x - r, y - r);
up->cp.x = x + cos(ang2 / 57.3) * r;
up->cp.y = y + sin(ang2 / 57.3) * r;
return;
}
void UParcn(UserPath *up, float x, float y, float r, float ang1, float ang2)
/* adds <x y r ang1 ang2 arcn> to user path and updates bounding box */
{
if (!((up->numberOfPoints + 5) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = dps_arcn;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
up->points[up->numberOfPoints++] = r;
up->points[up->numberOfPoints++] = ang1;
up->points[up->numberOfPoints++] = ang2;
checkBoundingBox(up, x + r, y + r);
checkBoundingBox(up, x - r, y - r);
up->cp.x = x + cos(ang2 / 57.3) * r;
up->cp.y = y + sin(ang2 / 57.3) * r;
return;
}
void UParct(UserPath *up, float x1, float y1, float x2, float y2, float r)
/* adds <x1 y1 x2 y2 r arct> to user path and updates bounding box */
{
if (!((up->numberOfPoints + 5) < up->max)) {
growUserPath(up);
}
up->ops[up->numberOfOps++] = dps_arcn;
up->points[up->numberOfPoints++] = x1;
up->points[up->numberOfPoints++] = y1;
up->points[up->numberOfPoints++] = x2;
up->points[up->numberOfPoints++] = y2;
up->points[up->numberOfPoints++] = r;
checkBoundingBox(up, x1, y1);
checkBoundingBox(up, x2, y2);
up->cp.x = x2;
up->cp.y = y2;
return;
}
void closePath(UserPath *up)
/* adds <closepath> to user path and updates bounding box */
{
up->ops[up->numberOfOps++] = dps_closepath;
return;
}